В рамках данной лабораторной работы вам предлагается проанализировать набор данных о студентах двух школ в Португалии.
В файле students_data.csv представлена информация о студентах, посещающих два курса - математику (Math) и поргутальский язык (Por). Некоторые студенты представлены в обоих курсах, некоторые - только в одном. Для каждого студента известны три оценки по курсу: оценка за первое полугодие (G1), оценка за второе полугодие (G2) и итоговая оценка за год (G3).
Requirement already satisfied: graphviz in /usr/local/lib/python3.7/dist-packages (0.10.1) Requirement already satisfied: wand in /usr/local/lib/python3.7/dist-packages (0.6.6) Reading package lists... Done Building dependency tree Reading state information... Done libmagickwand-dev is already the newest version (8:6.9.7.4+dfsg-16ubuntu6.9). 0 upgraded, 0 newly installed, 0 to remove and 39 not upgraded. Requirement already satisfied: xgboost in /usr/local/lib/python3.7/dist-packages (0.90) Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from xgboost) (1.19.5) Requirement already satisfied: scipy in /usr/local/lib/python3.7/dist-packages (from xgboost) (1.4.1)
(1044, 36)
Данные представлены признаками различных типов: числовыми, категориальными, упорядоченными категориальными.
Описание признаков:
G3) одинаково в обоих частях.Tip: Используйте свои наработки из Лабораторной работы №1.
Проверить на ошибочные значения
Key Item
---------- ---------------------------------------------------------------------
Subject ({'Math', 'Por'}, 2)
school ({'MS', 'GP'}, 2)
sex ({'m', 'F', 'M'}, 3)
address ({'U', 'R'}, 2)
famsize ({'GT3', 'LE3'}, 2)
Pstatus ({'t', 'A', 'T'}, 3)
Medu ({'1', '3', '2', 'o', '4', '0'}, 6)
Fedu ({'1', '3', '2', 'o', '4', '0'}, 6)
Mjob ({'services', 'teacher', 'at-home', 'other', 'health', 'at_home'}, 6)
Fjob ({'services', 'teacher', 'at-home', 'other', 'health', 'at_home'}, 6)
reason ({'reputation', 'other', 'home', 'course'}, 4)
guardian ({'futher', 'other', 'mother', 'father'}, 4)
schoolsup ({'yes', 'no'}, 2)
famsup ({'yes', 'no'}, 2)
paid ({'yes', 'no'}, 2)
activities ({'yes', 'no'}, 2)
nursery ({'yes', 'no'}, 2)
higher ({'yes', 'no'}, 2)
internet ({'yes', 'no'}, 2)
romantic ({nan, 'yes', 'no'}, 3)
cheating ({nan, 'yes', 'no'}, 3)
Key Item
---------- ----------------------------------------------------------
Subject ({'Math', 'Por'}, 2)
school ({'MS', 'GP'}, 2)
sex ({'F', 'M'}, 2)
address ({'U', 'R'}, 2)
famsize ({'GT3', 'LE3'}, 2)
Pstatus ({'A', 'T'}, 2)
Medu ({'1', '3', '2', '4', '0'}, 5)
Fedu ({'1', '3', '2', '4', '0'}, 5)
Mjob ({'services', 'teacher', 'other', 'health', 'at_home'}, 5)
Fjob ({'services', 'teacher', 'other', 'health', 'at_home'}, 5)
reason ({'reputation', 'other', 'home', 'course'}, 4)
guardian ({'other', 'mother', 'father'}, 3)
schoolsup ({'yes', 'no'}, 2)
famsup ({'yes', 'no'}, 2)
paid ({'yes', 'no'}, 2)
activities ({'yes', 'no'}, 2)
nursery ({'yes', 'no'}, 2)
higher ({'yes', 'no'}, 2)
internet ({'yes', 'no'}, 2)
romantic ({nan, 'yes', 'no'}, 3)
cheating ({nan, 'yes', 'no'}, 3)
Medu: int64 , Fedu: int64
Проверить на пропущенные значения
romantic 10 famrel 10 Dalc 10 Walc 10 cheating 700 dtype: int64
no 664 yes 370 NaN 10 Name: romantic, dtype: int64 4.0 508 5.0 283 3.0 167 2.0 46 1.0 30 NaN 10 Name: famrel, dtype: int64 1.0 719 2.0 194 3.0 69 5.0 26 4.0 26 NaN 10 Name: Dalc, dtype: int64 1.0 393 2.0 231 3.0 199 4.0 138 5.0 73 NaN 10 Name: Walc, dtype: int64 NaN 700 yes 175 no 169 Name: cheating, dtype: int64
0
famrel: 3.9361702127659575 Dalc: 1.4970986460348163 Walc: 2.2911025145067696
Основываясь на предыдующей работе, даатсет не содержит серьезных выбросов, способных крайне негативно повлиять на построение моделей
Категориальные признаки нужно привести к One-Hot-Encoded форме
Ground Truth значения
Данные для обучения
Без G1 признака
Learning data features (no G1): 44
Посмотрим какие признаки сильно коррелируют между собой, ведь это может ухудшить результаты обучения
Выведем признаки с высокой корреляцией
Pair Cov
-------------------------------------------- ---------
('Medu', 'Fedu') 0.642063
('Medu', 'is_Mjob_teacher') 0.452952
('Dalc', 'Walc') 0.626551
('is_Subject_Por', 'is_paid_no') 0.473453
('is_Mjob_services', 'is_Mjob_other') -0.428556
('is_Fjob_services', 'is_Fjob_other') -0.702118
('is_guardian_other', 'is_guardian_mother') -0.416173
('is_guardian_mother', 'is_guardian_father') -0.836005
('is_reason_reputation', 'is_reason_course') -0.46711
('is_reason_home', 'is_reason_course') -0.479456
Многие из коррелирующих признаков - взаимоисключающие one-hot encoded признаки и их изменять не стоит
Однако я обрачу внимание на взаимосвязь признаков Medu и Fedu, Dalc и Walc
В данном случае эти 4 признака можно свести к 2м путем объединения:
установлен random_state чтобы контролировать разбиение
Убедимся в правильности разбиения (в частности соотвествии y)
860 11 269 9 581 0 775 11 669 9 Name: G3, dtype: int64
Рассмотрим распределение G3 в выборках y_train и y_test
Мы можем видеть, что распределение G3 в y_train и y_test выборках одинаково
Train shape: (835, 43) Example:
array([ 1.77837403, -0.72568138, 0.0362296 , -0.40926236, 0.05351395,
-0.18409633, -1.8956647 , -1.77756101, 1.19804442, -0.03615913,
-1.25268941, 0.61472578, 1.13199857, -0.61657545, 1.59787092,
-2.72659924, 0.36042375, -0.80837203, 0.53534546, 1.00359929,
-0.49437974, -0.3095166 , -0.50747426, 0.75468462, 1.90085761,
-0.37303373, -0.79226278, -0.30718781, -0.48309685, -0.62583278,
-0.25505102, -1.1430791 , -0.19962605, 4.23996141, -0.27573706,
0.65558716, -0.54644333, 1.78773038, -0.34322668, -0.5925645 ,
-0.81039869, -0.88058892, 1.00376842])Test shape: (209, 43) Example:
array([ 0.20116499, -0.72568138, 0.0362296 , -0.40926236, 1.14337127,
0.77068897, -1.01432838, 1.03887816, -0.70439696, 1.62279005,
-1.25268941, 0.61472578, -0.88339334, -0.61657545, -0.62583278,
0.36675724, 0.36042375, -0.80837203, 0.53534546, -0.99641362,
-0.49437974, -0.3095166 , 1.97054331, 0.75468462, 1.90085761,
-0.37303373, -0.79226278, -0.30718781, -0.48309685, 1.59787092,
-0.25505102, -1.1430791 , -0.19962605, -0.2358512 , -0.27573706,
-1.5253502 , 1.83001594, 1.78773038, -0.34322668, -0.5925645 ,
-0.81039869, 0.63756335, 0.51016027])Решите задачу регрессии: постройте модель, предсказывающую итоговую оценку, которую получит студент по предмету (G3). При решении задачи нельзя использовать признак G2.
Для решения задачи примените следующие методы:
Для каждого метода выполните настройку гиперпараметров на кросс-валидации.
Оцените качество каждой модели на отложенной выборке, используйте различные метрики. Сравните модели и сделайте вывод о качестве решения задачи.
Задачу необходимо решить в двух вариантах: с использованием признака G1 и без него. Сравните качество решений в двух случаях.
В регрессионных моделях попробуйте дать интерпретацию весам признаков.
Alpha: 0.1 CPU times: user 248 ms, sys: 212 ms, total: 460 ms Wall time: 242 ms
Test
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 13.6048 │ 11.5461 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 3.68847 │ 3.39796 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 2.66373 │ 2.41408 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 1.89809 │ 1.70175 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 0.116701 │ 0.0880885 │ ╘══════════╧════════════════╧═══════════════╛
WEIGHTS G1 0.295871 is_Subject_Math -0.000000 is_paid_yes -0.000000 is_famsup_yes 0.000000 is_schoolsup_yes -0.000000 is_Pstatus_T -0.000000 is_famsize_GT3 -0.000000 is_address_U 0.000000 is_sex_M -0.000000 is_school_GP 0.000000 Pedu 0.000000 is_nursery_yes 0.000000 absences -0.000000 health -0.000000 goout -0.000000 freetime -0.000000 famrel 0.000000 failures -0.000000 studytime 0.000000 traveltime -0.000000 is_activities_yes 0.000000 is_higher_yes 0.000000 Alc -0.000000 is_Fjob_services -0.000000 is_reason_home 0.000000 is_reason_other -0.000000 is_reason_reputation 0.000000 is_reason_course -0.000000 is_guardian_father 0.000000 is_guardian_other -0.000000 is_guardian_mother -0.000000 is_Fjob_other -0.000000 is_Fjob_at_home -0.000000 is_internet_yes 0.000000 is_Fjob_teacher 0.000000 is_Fjob_health 0.000000 is_Mjob_other -0.000000 is_Mjob_services 0.000000 is_Mjob_at_home -0.000000 is_Mjob_teacher 0.000000 is_Mjob_health 0.000000 is_romantic_yes -0.000000 age -0.000000 dtype: float64
Метрики у модели очень слабые, а по весам можно видеть, что предсказание делается, основываясь только на G1 признаке - предыдущей оценке
No G1
Alpha: 29.900000000000002 CPU times: user 258 ms, sys: 223 ms, total: 481 ms Wall time: 259 ms
Test
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 15.4023 │ 13.0908 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 3.92457 │ 3.61813 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 2.8788 │ 2.61368 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 2.21078 │ 1.78922 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 0 │ -0.0339102 │ ╘══════════╧════════════════╧═══════════════╛
WEIGHTS Pedu 0.0 is_school_GP 0.0 is_activities_yes 0.0 is_paid_yes -0.0 is_famsup_yes -0.0 is_schoolsup_yes -0.0 is_Pstatus_T -0.0 is_famsize_GT3 -0.0 is_address_U 0.0 is_sex_M -0.0 is_Subject_Math -0.0 Alc -0.0 absences -0.0 health -0.0 goout -0.0 freetime -0.0 famrel 0.0 failures -0.0 studytime 0.0 traveltime -0.0 is_nursery_yes 0.0 is_higher_yes 0.0 is_internet_yes 0.0 is_romantic_yes -0.0 is_reason_home 0.0 is_reason_other -0.0 is_reason_reputation 0.0 is_reason_course -0.0 is_guardian_father 0.0 is_guardian_other -0.0 is_guardian_mother -0.0 is_Fjob_other -0.0 is_Fjob_services -0.0 is_Fjob_at_home -0.0 is_Fjob_teacher 0.0 is_Fjob_health 0.0 is_Mjob_other -0.0 is_Mjob_services 0.0 is_Mjob_at_home -0.0 is_Mjob_teacher 0.0 is_Mjob_health 0.0 age -0.0 dtype: float64
Убрав у модели G1 признак мы вовсе лешили ее возможности предсказывать - все веса равны нулю
Alpha: 28.6 CPU times: user 5.68 s, sys: 7.22 s, total: 12.9 s Wall time: 6.69 s
Test
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 4.60432 │ 4.91063 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 2.14577 │ 2.21599 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 1.42811 │ 1.59266 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 0.947277 │ 1.27257 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 0.701062 │ 0.61216 │ ╘══════════╧════════════════╧═══════════════╛
WEIGHTS G1 2.835659 is_Subject_Math -0.618114 failures -0.368477 health -0.228059 absences 0.218612 is_paid_yes 0.197687 is_romantic_yes -0.196752 goout -0.176093 famrel 0.158452 is_Pstatus_T -0.135200 is_address_U 0.126000 is_higher_yes 0.116390 is_Mjob_health 0.109009 traveltime 0.093330 Alc 0.088374 is_Mjob_services 0.074440 is_famsize_GT3 -0.072063 is_Fjob_services -0.066631 is_Mjob_at_home -0.060031 is_Mjob_other -0.055127 is_reason_home -0.054204 is_school_GP 0.053477 is_nursery_yes -0.052833 is_Fjob_other 0.050603 is_reason_course 0.048157 is_schoolsup_yes 0.042978 freetime -0.035239 is_internet_yes 0.034970 is_Mjob_teacher -0.033365 is_guardian_father 0.032680 is_activities_yes -0.028371 is_guardian_mother -0.027458 is_sex_M 0.020741 is_Fjob_health 0.019942 is_Fjob_at_home 0.017033 Pedu -0.013755 age -0.012560 is_Fjob_teacher -0.011470 studytime 0.010736 is_famsup_yes 0.006827 is_reason_other -0.004952 is_guardian_other -0.004532 is_reason_reputation 0.004077 dtype: float64
Данная линейная модель с Ridge регуляризацией показала хорошие результаты, судя по метрикам.
Также по весам можно понять, что модель использует все параметры для предсказания в разной мере.
Наиболее влияетельными оказались:
G1 (не удивительно)is_subject_Math (отрицательный вес показывает, что по математике оценка должны быть ниже)failures (больше пропускаешь - оценка ниже)No G1
Alpha: 29.900000000000002 CPU times: user 5.74 s, sys: 7.03 s, total: 12.8 s Wall time: 6.62 s
Test
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 10.704 │ 11.0084 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 3.2717 │ 3.3179 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 2.38736 │ 2.41881 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 1.72638 │ 1.87332 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 0.305035 │ 0.130556 │ ╘══════════╧════════════════╧═══════════════╛
WEIGHTS failures -1.065998 is_Subject_Math -0.947771 is_higher_yes 0.482705 studytime 0.427825 is_schoolsup_yes -0.393510 health -0.388848 is_school_GP 0.329083 goout -0.306595 is_Mjob_health 0.286244 is_romantic_yes -0.273986 is_famsize_GT3 -0.247504 famrel 0.239709 is_address_U 0.237777 is_famsup_yes -0.231084 is_Fjob_teacher 0.221638 is_Mjob_other -0.192995 is_Mjob_services 0.190275 is_Mjob_at_home -0.157597 Pedu 0.146618 Alc -0.137913 is_Fjob_services -0.123705 is_paid_yes 0.116387 absences 0.114731 is_internet_yes 0.108024 is_nursery_yes -0.100919 is_guardian_mother -0.088158 is_guardian_other 0.077666 is_Pstatus_T -0.073282 traveltime 0.055811 is_activities_yes 0.052456 freetime 0.051664 is_reason_reputation 0.051609 is_guardian_father 0.048765 age -0.042837 is_Fjob_at_home 0.042574 is_sex_M 0.035327 is_reason_other -0.031182 is_reason_home -0.021044 is_Fjob_other -0.010299 is_Fjob_health -0.009660 is_Mjob_teacher -0.009414 is_reason_course -0.006510 dtype: float64
Без признака G1 метрики стали сильно хуже, а большее влияение получили:
failuresis_higher_yesstudytimeCPU times: user 190 ms, sys: 50.9 ms, total: 241 ms Wall time: 13.9 s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('polynomialfeatures',
PolynomialFeatures(degree=2,
include_bias=False,
interaction_only=False,
order='C')),
('linearregression',
LinearRegression(copy_X=True,
fit_intercept=True,
n_jobs=None,
normalize=True))],
verbose=False),
iid='deprecated', n_jobs=-1,
param_grid={'polynomialfeatures__degree': [1, 2, 3]},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='neg_mean_squared_error', verbose=0)Best hyperparams
{'polynomialfeatures__degree': 1}Test
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 4.63996 │ 5.02588 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 2.15406 │ 2.24185 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 1.45921 │ 1.62587 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 0.973973 │ 1.2604 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 0.698748 │ 0.603057 │ ╘══════════╧════════════════╧═══════════════╛
Давайте убедимся в том, что выбранная степень полинома оптимальна.
Поставим degree=3 принудительно и сравним метрики
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 1.79099e-28 │ 7.14285 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 1.33828e-14 │ 2.67261 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 1.03539e-14 │ 1.97092 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 8.88178e-15 │ 1.54451 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 1 │ 0.43586 │ ╘══════════╧════════════════╧═══════════════╛
На метриках мы видим переобучение модели:
x_train выборке все метрики показывает минимально возможную ошибку, значит наша модель смогла построить функцию, чтобы "попасть" во все точки датасетаx_test выборке модель показывает плохую обобщающую способность, по крайней мере хуже обычной линейной моделиNo G1
CPU times: user 130 ms, sys: 17.4 ms, total: 147 ms Wall time: 10.6 s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('polynomialfeatures',
PolynomialFeatures(degree=2,
include_bias=False,
interaction_only=False,
order='C')),
('linearregression',
LinearRegression(copy_X=True,
fit_intercept=True,
n_jobs=None,
normalize=True))],
verbose=False),
iid='deprecated', n_jobs=-1,
param_grid={'polynomialfeatures__degree': [1, 2, 3]},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='neg_mean_squared_error', verbose=0){'polynomialfeatures__degree': 1}Test
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 10.698 │ 11.1208 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 3.27078 │ 3.33479 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 2.39404 │ 2.43725 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 1.73181 │ 1.89116 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 0.305429 │ 0.12168 │ ╘══════════╧════════════════╧═══════════════╛
Метрики сильно хуже моделей с G1 признаком
Давайте убедимся в том, что выбранная степень полинома оптимальна.
Поставим degree=3 принудительно и сравним метрики
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 2.20209e-28 │ 13.0745 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 1.48395e-14 │ 3.61587 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 1.16314e-14 │ 2.66703 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 8.88178e-15 │ 2.05421 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 1 │ -0.0326215 │ ╘══════════╧════════════════╧═══════════════╛
CPU times: user 1.7 s, sys: 41.2 ms, total: 1.74 s Wall time: 12.2 s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('kneighborsregressor',
KNeighborsRegressor(algorithm='auto',
leaf_size=30,
metric='minkowski',
metric_params=None,
n_jobs=None,
n_neighbors=5, p=2,
weights='uniform'))],
verbose=False),
iid='deprecated', n_jobs=-1,
param_grid={'kneighborsregr...
'brute'],
'kneighborsregressor__n_neighbors': array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]),
'kneighborsregressor__weights': ['uniform',
'distance']},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='neg_mean_absolute_error', verbose=0){'kneighborsregressor__algorithm': 'ball_tree',
'kneighborsregressor__n_neighbors': 26,
'kneighborsregressor__weights': 'distance'}Test
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 0 │ 8.46876 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 0 │ 2.91011 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 0 │ 2.01901 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 0 │ 1.42325 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 1 │ 0.33114 │ ╘══════════╧════════════════╧═══════════════╛
Так как KNN просто "запоминает" train выборку, то и метрики на ней наилучшие.
Однако на отложенных данных видим, что обобщающая способность далеко не лучшая
No G1
CPU times: user 2.04 s, sys: 70.9 ms, total: 2.11 s Wall time: 12.5 s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('kneighborsregressor',
KNeighborsRegressor(algorithm='auto',
leaf_size=30,
metric='minkowski',
metric_params=None,
n_jobs=None,
n_neighbors=5, p=2,
weights='uniform'))],
verbose=False),
iid='deprecated', n_jobs=-1,
param_grid={'kneighborsregr...
'brute'],
'kneighborsregressor__n_neighbors': array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]),
'kneighborsregressor__weights': ['uniform',
'distance']},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='neg_mean_absolute_error', verbose=0){'kneighborsregressor__algorithm': 'ball_tree',
'kneighborsregressor__n_neighbors': 26,
'kneighborsregressor__weights': 'distance'}Test
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 0 │ 10.6234 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 0 │ 3.25935 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 0 │ 2.32431 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 0 │ 1.6747 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 1 │ 0.160968 │ ╘══════════╧════════════════╧═══════════════╛
Без G1 параметра ожидаемо хуже
Также можно заметить, что grid.best_params_ такие же как и у моделей, обучаемых на выборке со всеми признаками
CPU times: user 11.8 s, sys: 766 ms, total: 12.6 s Wall time: 10min 40s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('randomforestregressor',
RandomForestRegressor(bootstrap=True,
ccp_alpha=0.0,
criterion='mse',
max_depth=None,
max_features='auto',
max_leaf_nodes=None,
max_samples=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
min_samples_leaf=...
189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201,
202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
241, 242, 243, 244, 245, 246, 247, 248, 249])},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='neg_mean_absolute_error', verbose=0){'randomforestregressor__max_features': 'auto',
'randomforestregressor__n_estimators': 218}SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 0.597778 │ 3.64406 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 0.773161 │ 1.90894 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 0.528149 │ 1.38912 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 0.380734 │ 1.00459 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 0.961189 │ 0.712193 │ ╘══════════╧════════════════╧═══════════════╛
Мы видим довольно сильное падение в качестве модели на test выборке
Можно поробовать избавиться от этого подобрав max_depth деревьев
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('randomforestregressor',
RandomForestRegressor(bootstrap=True,
ccp_alpha=0.0,
criterion='mse',
max_depth=None,
max_features='auto',
max_leaf_nodes=None,
max_samples=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
min_samples_leaf=...
n_estimators=218,
n_jobs=None,
oob_score=False,
random_state=None,
verbose=0,
warm_start=False))],
verbose=False),
iid='deprecated', n_jobs=-1,
param_grid={'randomforestregressor__max_depth': array([ 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34,
36, 38, 40, 42, 44, 46, 48])},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='neg_mean_absolute_error', verbose=0){'randomforestregressor__max_depth': 6}SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 1.8317 │ 3.59326 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 1.3534 │ 1.89559 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 1.00602 │ 1.38352 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 0.776568 │ 1.05151 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 0.881076 │ 0.716205 │ ╘══════════╧════════════════╧═══════════════╛
Получилось немного улучшить метрики
No G1
CPU times: user 6.3 s, sys: 454 ms, total: 6.75 s Wall time: 5min 26s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('randomforestregressor',
RandomForestRegressor(bootstrap=True,
ccp_alpha=0.0,
criterion='mse',
max_depth=None,
max_features='auto',
max_leaf_nodes=None,
max_samples=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
min_samples_leaf=...
'randomforestregressor__n_estimators': array([150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174,
176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200,
202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226,
228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248])},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='neg_mean_absolute_error', verbose=0){'randomforestregressor__max_features': 'auto',
'randomforestregressor__n_estimators': 176}Test
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 1.33962 │ 10.6123 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 1.15742 │ 3.25765 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 0.8408 │ 2.32433 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 0.602273 │ 1.60795 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 0.913025 │ 0.161843 │ ╘══════════╧════════════════╧═══════════════╛
RandomForestRegressor, обученный на данных без признака G1 имеет плохую обобщающую способность
{'randomforestregressor__max_depth': 32}Test
SCORES: ╒══════════╤════════════════╤═══════════════╕ │ metric │ train scores │ test scores │ ╞══════════╪════════════════╪═══════════════╡ │ mse │ 1.35514 │ 10.7822 │ ├──────────┼────────────────┼───────────────┤ │ rmse │ 1.1641 │ 3.28363 │ ├──────────┼────────────────┼───────────────┤ │ mae │ 0.842246 │ 2.34461 │ ├──────────┼────────────────┼───────────────┤ │ medae │ 0.614679 │ 1.64679 │ ├──────────┼────────────────┼───────────────┤ │ R2 │ 0.912017 │ 0.148425 │ ╘══════════╧════════════════╧═══════════════╛
Улучшить результаты не получилось
{'R2': 0.7162051857150782,
'mae': 1.3835179330702032,
'medae': 1.0515141031025337,
'mse': 3.5932616642774806,
'rmse': 1.895590057021159}╒═══════════════╤══════════╤═════════╤═════════╤═════════╤═══════════╕ │ estimators │ mse │ rmse │ mae │ medae │ R2 │ ╞═══════════════╪══════════╪═════════╪═════════╪═════════╪═══════════╡ │ losso │ 11.5461 │ 3.39796 │ 2.41408 │ 1.70175 │ 0.0880885 │ ├───────────────┼──────────┼─────────┼─────────┼─────────┼───────────┤ │ ridge │ 4.91063 │ 2.21599 │ 1.59266 │ 1.27257 │ 0.61216 │ ├───────────────┼──────────┼─────────┼─────────┼─────────┼───────────┤ │ poly │ 5.02588 │ 2.24185 │ 1.62587 │ 1.2604 │ 0.603057 │ ├───────────────┼──────────┼─────────┼─────────┼─────────┼───────────┤ │ knn │ 8.46876 │ 2.91011 │ 2.01901 │ 1.42325 │ 0.33114 │ ├───────────────┼──────────┼─────────┼─────────┼─────────┼───────────┤ │ random forest │ 3.59326 │ 1.89559 │ 1.38352 │ 1.05151 │ 0.716205 │ ╘═══════════════╧══════════╧═════════╧═════════╧═════════╧═══════════╛
Best Regression (G1)
model: RandomForestRegressor
params: n_estimators=218, max_depth=6
score (R2): 0.716
╒═══════════════╤═════════╤═════════╤═════════╤═════════╤════════════╕ │ estimators │ mse │ rmse │ mae │ medae │ R2 │ ╞═══════════════╪═════════╪═════════╪═════════╪═════════╪════════════╡ │ losso │ 13.0908 │ 3.61813 │ 2.61368 │ 1.78922 │ -0.0339102 │ ├───────────────┼─────────┼─────────┼─────────┼─────────┼────────────┤ │ ridge │ 11.0084 │ 3.3179 │ 2.41881 │ 1.87332 │ 0.130556 │ ├───────────────┼─────────┼─────────┼─────────┼─────────┼────────────┤ │ poly │ 13.0745 │ 3.61587 │ 2.66703 │ 2.05421 │ -0.0326215 │ ├───────────────┼─────────┼─────────┼─────────┼─────────┼────────────┤ │ knn │ 10.6234 │ 3.25935 │ 2.32431 │ 1.6747 │ 0.160968 │ ├───────────────┼─────────┼─────────┼─────────┼─────────┼────────────┤ │ random forest │ 10.8576 │ 3.29509 │ 2.35762 │ 1.62844 │ 0.142469 │ ╘═══════════════╧═════════╧═════════╧═════════╧═════════╧════════════╛
Best Regression (no G1)
model: KNeighborsRegressor
params: n_neighbors=26, algorithm="ball_tree", weights="distance"
score (R2): 0.16
Решите задачу бинарной классификации: постройте модель, предсказывающую, сдаст студент предмет (G3 >= 8) или не сдаст (G3 < 8).
При решении задачи нельзя использовать признаки G1 и G2.
Уберем из использования G1
Создадим новый признак для предсказания
860 1
269 1
581 0
775 1
669 1
..
866 0
742 1
74 0
176 1
338 1
Name: G3, Length: 835, dtype: int64Проверим распредление
Train: 1 0.894611 0 0.105389 Name: G3, dtype: float64 Test: 1 0.942584 0 0.057416 Name: G3, dtype: float64
Распределение практически одинаковое и не будет негавтино влиять на процесс обучения
5-fold validation
CV MEAN SCORE: 0.8802395209580839 All scores: 0.862, 0.874, 0.868, 0.904, 0.892
Visualize
Compare trees
На кросс-валидации (5-fold из 2 повторений) оцените, как меняется качество модели Random Forest с ростом числа деревьев (при дефолтных значениях остальных параметров). Провизуализируйте результаты. Сколько деревьев достаточно в данном случае и почему?
NB: В сравнение включите конфигурацию, аналогичную простому дереву решений.
Вывод:
Основываясь на полученном графике оптимальное количество деревьев находится в районе 7-10
CPU times: user 3.19 s, sys: 134 ms, total: 3.33 s Wall time: 47.9 s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('randomforestclassifier',
RandomForestClassifier(bootstrap=True,
ccp_alpha=0.0,
class_weight=None,
criterion='gini',
max_depth=None,
max_features='auto',
max_leaf_nodes=None,
max_samples=None,
min_impurity_decrease=0.0,
min_impurity_split=N...
warm_start=False))],
verbose=False),
iid='deprecated', n_jobs=-1,
param_grid={'randomforestclassifier__criterion': ['gini',
'entropy'],
'randomforestclassifier__max_depth': [2, 3, 4, 5, 10,
15, None],
'randomforestclassifier__n_estimators': [1, 2, 3, 4, 5,
6, 7, 8, 9,
10, 12, 15,
17, 20, 25,
40, 75,
100]},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='f1', verbose=0){'randomforestclassifier__criterion': 'entropy',
'randomforestclassifier__max_depth': None,
'randomforestclassifier__n_estimators': 20}0.9474470250793129
RandomForestClassifier(bootstrap=True, ccp_alpha=0.0, class_weight=None,
criterion='entropy', max_depth=None, max_features='auto',
max_leaf_nodes=None, max_samples=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=20,
n_jobs=None, oob_score=False, random_state=None,
verbose=0, warm_start=False)F1: 0.9752475247524752
precision recall f1-score support
0 1.00 0.17 0.29 12
1 0.95 1.00 0.98 197
accuracy 0.95 209
macro avg 0.98 0.58 0.63 209
weighted avg 0.95 0.95 0.94 209
0 0.918206 1 0.901333 2 0.938144 3 0.930591 4 0.936061 5 0.941176 6 0.929870 7 0.923483 8 0.934726 9 0.948980 10 0.932292 11 0.920213 12 0.940568 13 0.927461 14 0.938462 15 0.915789 16 0.927083 17 0.924282 18 0.927083 19 0.918635 dtype: float64
Вывод:
f1 score ансамбля - 0.975
f1 scores деревьев - большинство значений расположены в промежутке от 0.92-0.94
Каждое дерево по отдельности предсказывает результат хуже, чем в ансамбле.
CPU times: user 316 ms, sys: 25.6 ms, total: 342 ms Wall time: 7.74 s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('logisticregression',
LogisticRegression(C=1.0,
class_weight=None,
dual=False,
fit_intercept=True,
intercept_scaling=1,
l1_ratio=None,
max_iter=1000,
multi_class='auto',
n_jobs=None,
penalty='l2',
random_state=None,
solver='lbfgs',
tol=0.0001,
verbose=0,
warm_start=False))],
verbose=False),
iid='deprecated', n_jobs=-1,
param_grid={'logisticregression__class_weight': ['balanced', None],
'logisticregression__multi_class': ['ovr',
'multinomial'],
'logisticregression__solver': ['newton-cg', 'lbfgs',
'saga', 'sag',
'liblinear']},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='roc_auc', verbose=0){'logisticregression__class_weight': None,
'logisticregression__multi_class': 'ovr',
'logisticregression__solver': 'liblinear'}0.7545297976930533
Logistic
0.7598481379128833
array([0.77568627, 0.78156863, 0.81058911, 0.70357942, 0.78001491,
0.81686275, 0.68745098, 0.81319911, 0.68941089, 0.74011931])Random Forest
0.7790725095407289
array([0.72117647, 0.82823529, 0.8264355 , 0.71290082, 0.80406413,
0.84784314, 0.77490196, 0.65604027, 0.8310962 , 0.78803132])Random Forest показывает результат немного лучше
Вывод:Random Forest покала себя лучше Logistic Regression
как на 5-fold валидации так и во время теста на отложенной выборке
RFC-ROC-AUC: 0.87
LR-ROC-AUC: 0.78
Значение f1-score практически не меняются от увеличения количества деревьев
CPU times: user 15.3 s, sys: 848 ms, total: 16.1 s Wall time: 7min 20s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('xgbclassifier',
XGBClassifier(base_score=0.5,
booster='gbtree',
colsample_bylevel=1,
colsample_bynode=1,
colsample_bytree=1,
gamma=0,
learning_rate=0.1,
max_delta_step=0,
max_depth=3,
min_child_weight=1,
missing=None,
n_estimators=100,
n_jobs...
verbose=False),
iid='deprecated', n_jobs=-1,
param_grid={'xgbclassifier__gamma': [0, 1, 2, 5, 10],
'xgbclassifier__max_depth': array([ 1, 3, 5, 7, 9, 11, 13]),
'xgbclassifier__n_eta': array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]),
'xgbclassifier__sampling_method': ['uniform',
'gradient_based']},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='f1', verbose=0){'xgbclassifier__gamma': 0,
'xgbclassifier__max_depth': 3,
'xgbclassifier__n_eta': 0.0,
'xgbclassifier__sampling_method': 'uniform'}0.9529755437469822
F1 score: 0.9698492462311556
precision recall f1-score support
0 0.50 0.33 0.40 12
1 0.96 0.98 0.97 197
accuracy 0.94 209
macro avg 0.73 0.66 0.68 209
weighted avg 0.93 0.94 0.94 209
Вывод:XGBClassifier оказался лучше как Random Forest, так и Logistic Regression
Модель хорошо предсказывает оба класса, несмотря на низкий support
XGBC-ROC-AUC: 0.89
XGBC-F1: 0.97
RFC-ROC-AUC: 0.87
LR-ROC-AUC: 0.78
Решите задачу многоклассовой классификации: постройте модель, пресдказывающую оценку студента по предмету по 4 балльной шкале
G3 <= 20G3 <= 17G3 <= 13G3 < 8 При решении задачи нельзя использовать признаки G1 и G2.
Для решения задачи примените следующие методы:
На кросс-валидации подберите оптимальные значения гиперпараметров алгоритмов.
Целевая переменная будет представлена следующими классами:
860 2
269 2
581 3
775 2
669 2
..
866 3
742 2
74 3
176 1
338 2
Name: G3, Length: 835, dtype: int64640 1
722 1
914 2
731 2
688 2
..
233 2
794 2
898 3
416 2
870 1
Name: G3, Length: 209, dtype: int64Убираем G1 признак
Рассмотрим распределение G3 в выборках y_train и y_test
Мы можем видеть, что распределение G3 в y_train и y_test выборках одинаково
CPU times: user 2.77 s, sys: 122 ms, total: 2.9 s Wall time: 21.7 s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('kneighborsclassifier',
KNeighborsClassifier(algorithm='auto',
leaf_size=30,
metric='minkowski',
metric_params=None,
n_jobs=None,
n_neighbors=5, p=2,
weights='uniform'))],
verbose=False),
iid='deprecated', n_jobs=-1,
param_grid={'kneighborscl...
'kd_tree',
'brute'],
'kneighborsclassifier__n_neighbors': array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]),
'kneighborsclassifier__weights': ['uniform',
'distance']},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='f1_weighted', verbose=0){'kneighborsclassifier__algorithm': 'ball_tree',
'kneighborsclassifier__n_neighbors': 3,
'kneighborsclassifier__weights': 'distance'}TRAIN:
precision recall f1-score support
0 1.00 1.00 1.00 29
1 1.00 1.00 1.00 199
2 1.00 1.00 1.00 519
3 1.00 1.00 1.00 88
accuracy 1.00 835
macro avg 1.00 1.00 1.00 835
weighted avg 1.00 1.00 1.00 835
TEST:
precision recall f1-score support
0 0.50 0.17 0.25 6
1 0.54 0.52 0.53 60
2 0.76 0.80 0.78 131
3 0.18 0.17 0.17 12
accuracy 0.67 209
macro avg 0.50 0.41 0.43 209
weighted avg 0.65 0.67 0.66 209
Так как KNN запоминает всю train выборку, то и оценки на ней будут максимальные.
Если же смотреть на результаты предсказания на test выборке,
то видна главная проблема - классы 0 и 1, у которых низкий
support (количество примеров, представлоенных в выборке),
ожидаемо предсказываются хуже, из за чего портится общая оценка классификатора.
CPU times: user 556 ms, sys: 116 ms, total: 672 ms Wall time: 16.5 s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('logisticregression',
LogisticRegression(C=1.0,
class_weight=None,
dual=False,
fit_intercept=True,
intercept_scaling=1,
l1_ratio=None,
max_iter=1000,
multi_class='auto',
n_jobs=None,
penalty='l2',
random_state=None,
solver='lbfgs',
tol=0.0001,
verbose=0,
warm_start=False))],
verbose=False),
iid='deprecated', n_jobs=-1,
param_grid={'logisticregression__class_weight': ['balanced', None],
'logisticregression__multi_class': ['ovr',
'multinomial'],
'logisticregression__solver': ['newton-cg', 'lbfgs',
'saga', 'sag']},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='f1_weighted', verbose=0){'logisticregression__class_weight': None,
'logisticregression__multi_class': 'ovr',
'logisticregression__solver': 'newton-cg'}TRAIN:
precision recall f1-score support
0 1.00 0.03 0.07 29
1 0.56 0.43 0.49 199
2 0.71 0.88 0.79 519
3 0.70 0.30 0.42 88
accuracy 0.68 835
macro avg 0.74 0.41 0.44 835
weighted avg 0.68 0.68 0.65 835
TEST:
precision recall f1-score support
0 0.00 0.00 0.00 6
1 0.56 0.38 0.46 60
2 0.70 0.84 0.76 131
3 0.33 0.25 0.29 12
accuracy 0.65 209
macro avg 0.40 0.37 0.38 209
weighted avg 0.62 0.65 0.62 209
Предсказания классов с низким support свойтсвенно также как и KNN, однако в этот раз класс 0 не предсказывается вовсе - все метрики равны нулю.
CPU times: user 6.76 s, sys: 94 ms, total: 6.85 s Wall time: 19.1 s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('decisiontreeclassifier',
DecisionTreeClassifier(ccp_alpha=0.0,
class_weight=None,
criterion='gini',
max_depth=None,
max_features=None,
max_leaf_nodes=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
min_samples_leaf=1,
min_samples...
'decisiontreeclassifier__max_depth': [2, 3, 4, 5, 10,
12, 15, 17, 20,
30, None],
'decisiontreeclassifier__max_features': ['auto',
'sqrt',
'log2'],
'decisiontreeclassifier__min_samples_split': array([2, 3, 4, 5, 6, 7, 8, 9]),
'decisiontreeclassifier__random_state': [13],
'decisiontreeclassifier__splitter': ['best',
'random']},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='f1_weighted', verbose=0){'decisiontreeclassifier__criterion': 'gini',
'decisiontreeclassifier__max_depth': 12,
'decisiontreeclassifier__max_features': 'auto',
'decisiontreeclassifier__min_samples_split': 4,
'decisiontreeclassifier__random_state': 13,
'decisiontreeclassifier__splitter': 'random'}TRAIN:
precision recall f1-score support
0 0.59 0.45 0.51 29
1 0.75 0.55 0.63 199
2 0.80 0.94 0.86 519
3 0.91 0.58 0.71 88
accuracy 0.79 835
macro avg 0.76 0.63 0.68 835
weighted avg 0.79 0.79 0.78 835
TEST:
precision recall f1-score support
0 0.00 0.00 0.00 6
1 0.56 0.48 0.52 60
2 0.72 0.75 0.73 131
3 0.12 0.17 0.14 12
accuracy 0.62 209
macro avg 0.35 0.35 0.35 209
weighted avg 0.62 0.62 0.61 209
Снова видим нулевые метрики для 0 класса
CPU times: user 10.7 s, sys: 704 ms, total: 11.4 s Wall time: 5min 28s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('randomforestclassifier',
RandomForestClassifier(bootstrap=True,
ccp_alpha=0.0,
class_weight=None,
criterion='gini',
max_depth=None,
max_features='auto',
max_leaf_nodes=None,
max_samples=None,
min_impurity_decrease=0.0,
min_impurity_split=N...
iid='deprecated', n_jobs=-1,
param_grid={'randomforestclassifier__max_depth': [2, 3, 4, 5, 10,
15, 20, 30, 50,
None],
'randomforestclassifier__n_estimators': array([ 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110,
115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175,
180, 185, 190, 195])},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='f1_weighted', verbose=0){'randomforestclassifier__max_depth': 30,
'randomforestclassifier__n_estimators': 65}TRAIN:
precision recall f1-score support
0 1.00 1.00 1.00 29
1 1.00 1.00 1.00 199
2 1.00 1.00 1.00 519
3 1.00 1.00 1.00 88
accuracy 1.00 835
macro avg 1.00 1.00 1.00 835
weighted avg 1.00 1.00 1.00 835
TEST:
precision recall f1-score support
0 0.00 0.00 0.00 6
1 0.56 0.38 0.46 60
2 0.71 0.89 0.79 131
3 0.50 0.17 0.25 12
accuracy 0.67 209
macro avg 0.44 0.36 0.37 209
weighted avg 0.64 0.67 0.64 209
Судя по оценкам, полученным на train выборке, модель переобучилась.
Однако после эксперементов с гиперпараметрами выяснилось, что `testz метрики данной модели лучше.
CPU times: user 23.1 s, sys: 2.47 s, total: 25.5 s Wall time: 57min 27s
GridSearchCV(cv=KFold(n_splits=5, random_state=None, shuffle=True),
error_score=nan,
estimator=Pipeline(memory=None,
steps=[('gradientboostingclassifier',
GradientBoostingClassifier(ccp_alpha=0.0,
criterion='friedman_mse',
init=None,
learning_rate=0.1,
loss='deviance',
max_depth=3,
max_features=None,
max_leaf_nodes=None,
min_impurity_decrease=0.0,
min_impurity_sp...
'gradientboostingclassifier__loss': ['deviance',
'exponential'],
'gradientboostingclassifier__max_features': ['auto',
'sqrt',
'log2'],
'gradientboostingclassifier__n_estimators': array([ 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110,
115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175,
180, 185, 190, 195])},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='f1_weighted', verbose=0){'gradientboostingclassifier__criterion': 'mse',
'gradientboostingclassifier__loss': 'deviance',
'gradientboostingclassifier__max_features': 'log2',
'gradientboostingclassifier__n_estimators': 145}TRAIN:
precision recall f1-score support
0 1.00 0.62 0.77 29
1 0.87 0.78 0.82 199
2 0.88 0.97 0.92 519
3 0.97 0.72 0.82 88
accuracy 0.88 835
macro avg 0.93 0.77 0.83 835
weighted avg 0.89 0.88 0.88 835
TEST:
precision recall f1-score support
0 0.00 0.00 0.00 6
1 0.51 0.38 0.44 60
2 0.72 0.85 0.78 131
3 0.33 0.25 0.29 12
accuracy 0.66 209
macro avg 0.39 0.37 0.38 209
weighted avg 0.62 0.66 0.63 209
╒═══════════════════╤═══════════════════╤══════════════════════╤════════════════╤═══════════════════╤════════════╤═══════════════╤════════════╕ │ estimators │ precision_macro │ precision_weighted │ recall_macro │ recall_weighted │ f1_macro │ f1_weighted │ accuracy │ ╞═══════════════════╪═══════════════════╪══════════════════════╪════════════════╪═══════════════════╪════════════╪═══════════════╪════════════╡ │ knn │ 0.495268 │ 0.654403 │ 0.412882 │ 0.665072 │ 0.432901 │ 0.656798 │ 0.665072 │ ├───────────────────┼───────────────────┼──────────────────────┼────────────────┼───────────────────┼────────────┼───────────────┼────────────┤ │ log-regression │ 0.397628 │ 0.61656 │ 0.368257 │ 0.650718 │ 0.375601 │ 0.624299 │ 0.650718 │ ├───────────────────┼───────────────────┼──────────────────────┼────────────────┼───────────────────┼────────────┼───────────────┼────────────┤ │ decistion-tree │ 0.347667 │ 0.615222 │ 0.349523 │ 0.617225 │ 0.346783 │ 0.614988 │ 0.617225 │ ├───────────────────┼───────────────────┼──────────────────────┼────────────────┼───────────────────┼────────────┼───────────────┼────────────┤ │ random-forest │ 0.443158 │ 0.635816 │ 0.358874 │ 0.674641 │ 0.37364 │ 0.639717 │ 0.674641 │ ├───────────────────┼───────────────────┼──────────────────────┼────────────────┼───────────────────┼────────────┼───────────────┼────────────┤ │ gradient-boosting │ 0.391306 │ 0.617649 │ 0.370165 │ 0.655502 │ 0.375689 │ 0.630413 │ 0.655502 │ ╘═══════════════════╧═══════════════════╧══════════════════════╧════════════════╧═══════════════════╧════════════╧═══════════════╧════════════╛
Best Multiclass Classifier
Выводы:
результаты обучения всех моделей сильно зависит от
набора данных и распределения целевых значений в нем
Способность предсказывать конкретный класс уменьшается с уменьшием
встречающихся примеров (support), иногда вовсе до нуля
Среди обученных моделей я бы выделил KNN и Random Forest.
Данные модели показали наилучшие метрики (accuracy + f1).
Однако KNN с преимуществом над RF определяет нулевой класс с крайне низким support.
model: RandomForestRegressor
params: n_estimators=65, max_depth=30
score (accuracy/f1): 0.67 / 0/64
model: KNeighborsClassifier
params: algorithm='ball_tree', n_neighbors=3, weights='distance'
score (accuracy/f1): 0.66 / 0/66